package com.work.game.volley.commonadapter;

import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ProgressBar;

import java.util.ArrayList;
import java.util.List;

public abstract class BaseCommonAdapter<T> extends BaseAdapter implements
		OnLongClickListener, OnItemClickListener {

	protected Context context;
	protected List<T> data;
	protected int layoutItemId;
	protected boolean displayIndeterminateProgress = false;

	/**
	 * Create a Adapter
	 * 
	 * @param context
	 *            The context
	 * @param layoutItemRes
	 *            The layout resource id of each item
	 */
	public BaseCommonAdapter(Context context, int layoutItemRes) {
		this(context, null, layoutItemRes);
	}

	/**
	 * Create a Adapter
	 * 
	 * @param context
	 *            The context
	 * @param data
	 *            A new list is created out of the one to avoid mutable list
	 * @param layoutItemId
	 *            The layout resource id of each item
	 */
	public BaseCommonAdapter(Context context, List<T> data, int layoutItemId) {
		this.context = context;
		this.data = data == null ? new ArrayList<T>() : new ArrayList<T>(data);
		this.layoutItemId = layoutItemId;
	}

	protected MultiItemTypeSupport<T> mMultiItemTypeSupport;

	protected void setMultiItemTypeSupport(
			MultiItemTypeSupport<T> itemTypeSupport) {
		this.mMultiItemTypeSupport = itemTypeSupport;
	}

	public BaseCommonAdapter(Context context, List<T> data,
			MultiItemTypeSupport<T> mMultiItemTypeSupport) {
		this.mMultiItemTypeSupport = mMultiItemTypeSupport;
		this.data = data == null ? new ArrayList<T>() : new ArrayList<T>(data);
		this.context = context;
	}

	@Override
	public int getCount() {
		int extra = displayIndeterminateProgress ? 1 : 0;
		return data.size() + extra;
	}

	@Override
	public T getItem(int position) {
		if (position >= data.size()) {
			return null;
		}
		return data.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public int getViewTypeCount() {
		if (mMultiItemTypeSupport != null) {
			return mMultiItemTypeSupport.getItemViewTypeCount() + 1;
		}
		return 2;
	}

	@Override
	public int getItemViewType(int position) {
		if (displayIndeterminateProgress) {
			if (mMultiItemTypeSupport != null) {
				return position >= data.size() ? 0 : mMultiItemTypeSupport
						.getItemViewType(position, data.get(position));
			}
		} else {
			if (mMultiItemTypeSupport != null)
				return mMultiItemTypeSupport.getItemViewType(position,
						data.get(position));
		}
		return position >= data.size() ? 0 : 1;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if (getItemViewType(position) == 0) {
			return creatIndeterminateProgressView(convertView, parent);
		}
		ViewHolder holder = getViewHolderManager(position, convertView, parent);
		T item = getItem(position);
		holder.setAssociatedObject(item);
		convertView(holder, data.get(position));
		return holder.getConvertView();
	}

	/**
	 * You can override this method to use a custom ViewHolder in order to fit
	 * your needs
	 * 
	 * @param position
	 *            The position of the item within the adapter's data set of the
	 *            item whose view we want.
	 * @param convertView
	 *            The old view to reuse, if possible. Note: You should check
	 *            that this view is non-null and of an appropriate type before
	 *            using. If it is not possible to convert this view to display
	 *            the correct data, this method can create a new view.
	 *            Heterogeneous lists can specify their number of view types, so
	 *            that this View is always of the right type (see
	 *            {@link #getViewTypeCount()} and {@link #getItemViewType(int)}
	 *            ).
	 * @param parent
	 *            The parent that this view will eventually be attached to
	 * @return An instance of ViewHolder
	 */
	protected ViewHolder getViewHolderManager(int position, View convertView,
			ViewGroup parent) {
		if (mMultiItemTypeSupport != null) {
			return ViewHolder.getViewHolder(
					context,
					convertView,
					parent,
					mMultiItemTypeSupport.getLayoutItemRes(position,
							data.get(position)), position);
		} else {
			return ViewHolder.getViewHolder(context, convertView, parent,
					layoutItemId, position);
		}
	}

	private View creatIndeterminateProgressView(View convertView,
			ViewGroup parent) {
		if (convertView == null) {
			FrameLayout container = new FrameLayout(context);
			container.setForegroundGravity(Gravity.CENTER);
			ProgressBar progress = new ProgressBar(context);
			container.addView(progress);
			convertView = container;
		}
		return convertView;
	}

	/**
	 * Implement this method and use the helper to adapt the view to the given
	 * item
	 * 
	 * @param helper
	 *            A fully initialized helper
	 * @param item
	 *            The item that needs to be displayed
	 */
	public abstract void convertView(ViewHolder holder, T t);

	@Override
	public boolean isEnabled(int position) {
		return position < data.size();
	}

	public void add(T elem) {
		data.add(elem);
		notifyDataSetChanged();
	}

	public void addAll(List<T> elems) {
		data.addAll(elems);
		notifyDataSetChanged();
	}

	public void set(T oldElem, T newElem) {
		set(data.indexOf(oldElem), newElem);
	}

	public void set(int indexOf, T newElem) {
		data.set(indexOf, newElem);
		notifyDataSetChanged();
	}

	public void setNewList(List<T> datas) {
		this.data = datas == null ? new ArrayList<T>()
				: new ArrayList<T>(datas);
		notifyDataSetChanged();
	}

	public void remover(T elem) {
		data.remove(elem);
		notifyDataSetChanged();
	}

	public void remover(int index) {
		data.remove(index);
		notifyDataSetChanged();
	}

	public void replaceAll(List<T> elem) {
		data.clear();
		data.addAll(elem);
		notifyDataSetChanged();
	}

	public boolean contains(T elem) {
		return data.contains(elem);
	}

	public void clear() {
		data.clear();
		notifyDataSetChanged();
	}

	public void showIndeterminateProgress(boolean display) {
		if (display == displayIndeterminateProgress)
			return;
		displayIndeterminateProgress = display;
		notifyDataSetChanged();
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position,
			long id) {

	}

	@Override
	public boolean onLongClick(View v) {
		return false;
	}

}
